﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

using vJine.Core.ORM;
using System.Data.Common;
using System.Data;

namespace vJine.Core.IoC {

    #region Opc

    public partial class Emit {
        #region Helpers

        static readonly Dictionary<Type, OpCode> ld_Ref = new Dictionary<Type, OpCode>();
        static readonly Dictionary<Type, OpCode> st_Ref = new Dictionary<Type, OpCode>();
        static void Init_Ref() {
            ld_Ref.Add(typeof(bool), OpCodes.Ldind_I1);
            ld_Ref.Add(typeof(sbyte), OpCodes.Ldind_I1);
            ld_Ref.Add(typeof(byte), OpCodes.Ldind_U1);
            ld_Ref.Add(typeof(char), OpCodes.Ldind_U2);
            ld_Ref.Add(typeof(short), OpCodes.Ldind_I2);
            ld_Ref.Add(typeof(ushort), OpCodes.Ldind_U2);
            ld_Ref.Add(typeof(int), OpCodes.Ldind_I4);
            ld_Ref.Add(typeof(uint), OpCodes.Ldind_U4);
            ld_Ref.Add(typeof(long), OpCodes.Ldind_I8);
            ld_Ref.Add(typeof(ulong), OpCodes.Ldind_I8);
            ld_Ref.Add(typeof(float), OpCodes.Ldind_R4);
            ld_Ref.Add(typeof(double), OpCodes.Ldind_R8);

            st_Ref.Add(typeof(bool), OpCodes.Stind_I1);
            st_Ref.Add(typeof(sbyte), OpCodes.Stind_I1);
            st_Ref.Add(typeof(byte), OpCodes.Stind_I1);
            st_Ref.Add(typeof(char), OpCodes.Stind_I2);
            st_Ref.Add(typeof(short), OpCodes.Stind_I2);
            st_Ref.Add(typeof(ushort), OpCodes.Stind_I2);
            st_Ref.Add(typeof(int), OpCodes.Stind_I4);
            st_Ref.Add(typeof(uint), OpCodes.Stind_I4);
            st_Ref.Add(typeof(long), OpCodes.Stind_I8);
            st_Ref.Add(typeof(ulong), OpCodes.Stind_I8);
            st_Ref.Add(typeof(float), OpCodes.Stind_R4);
            st_Ref.Add(typeof(double), OpCodes.Stind_R8);
        }

        static ConstructorInfo ctorDecimal =
            Reflect.@decimal.GetConstructor(new Type[] { Reflect.@int });
        static FieldInfo fldDateTimeMinValue = Reflect.DateTime.GetField("MinValue");
        static MethodInfo miTgetHandle = Reflect.@type.GetMethod("GetTypeFromHandle");
        static MethodInfo miMakeByRef = Reflect.@type.GetMethod("MakeByRefType", Type.EmptyTypes);
        static PropertyInfo pAssemblyQualifiedName = Reflect.GetProperty(Reflect.@type, "AssemblyQualifiedName");
        #endregion Helpers

        static Emit() {
            Emit.Init_Ref();
        }

        static MethodInfo activator_create = 
            new Call<int>(Activator.CreateInstance<int>).Method.GetGenericMethodDefinition();
        public static void Opc_Init(ILGenerator ilGen, Type tObject) {
            if (tObject == Reflect.@bool || tObject == Reflect.@sbyte || tObject == Reflect.@byte || tObject == Reflect.@char ||
                tObject == Reflect.@short || tObject == Reflect.@ushort || tObject == Reflect.@int || tObject == Reflect.@uint) {
                ilGen.Emit(OpCodes.Ldc_I4_0);
            } else if (tObject == Reflect.@long || tObject == Reflect.@ulong) {
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Conv_I8);
            } else if (tObject == Reflect.@float) {
                ilGen.Emit(OpCodes.Ldc_R4, 0.0F);
            } else if (tObject == Reflect.@double) {
                ilGen.Emit(OpCodes.Ldc_R8, 0.0D);
            } else if (tObject == Reflect.@decimal) {
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Newobj, ctorDecimal);
            } else if (tObject == Reflect.DateTime) {
                ilGen.Emit(OpCodes.Ldsfld, fldDateTimeMinValue);
            } else {
                ilGen.Emit(OpCodes.Call,
                    activator_create.MakeGenericMethod(tObject));
            }
        }

        public static void Opc_Conv(ILGenerator ilGen, Type tObj) {
            Emit.Opc_Conv(ilGen, tObj, false);
        }

        public static void Opc_Conv(ILGenerator ilGen, Type tObj, bool CheckOverflow) {
            if (tObj == Reflect.@sbyte) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
            } else if (tObj == Reflect.@byte) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I1_Un : OpCodes.Conv_I1);
            } else if (tObj == Reflect.@short) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
            } else if (tObj == Reflect.@ushort) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U2_Un : OpCodes.Conv_U2);
            } else if (tObj == Reflect.@int) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4);
            } else if (tObj == Reflect.@uint) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U4_Un : OpCodes.Conv_U4);
            } else if (tObj == Reflect.@long) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8);
            } else if (tObj == Reflect.@ulong) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U8_Un : OpCodes.Conv_U8);
            } else if (tObj == Reflect.@float) {
                ilGen.Emit(OpCodes.Conv_R4);
            } else if (tObj == Reflect.@double) {
                ilGen.Emit(OpCodes.Conv_R8);
            } else {
                throw new CoreException("UnSupported Type[{0}] For Opcodes.Conv", Reflect.GetTypeName(tObj));
            }
        }

        public static bool Opc_Conv(ILGenerator ilGen, Type tNumberA, Type tNumberB, bool CheckOverflow = false) {
            if(tNumberA == Reflect.@sbyte && tNumberB == Reflect.@byte) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
                return true;
            } else if(tNumberA == Reflect.@byte && tNumberB == Reflect.@sbyte) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
                return true;
            } else if(tNumberA == Reflect.@short && tNumberB == Reflect.@ushort) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
                return true;
            } else if(tNumberA == Reflect.@ushort && tNumberB == Reflect.@short) {
                ilGen.Emit(CheckOverflow ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
                return true;
            } else {
                return false;
            }
        }

        public static bool Opc_Conv(ILGenerator ilGen, Type tNumberA, DbType tNumberB, bool CheckOverflow = false) {
            switch(tNumberB) {
                case DbType.SByte:
                    return Emit.Opc_Conv(ilGen, tNumberA, Reflect.@sbyte, CheckOverflow);
                case DbType.Byte:
                    return Emit.Opc_Conv(ilGen, tNumberA, Reflect.@byte, CheckOverflow);
                case DbType.Int16:
                    return Emit.Opc_Conv(ilGen, tNumberA, Reflect.@short, CheckOverflow);
                case DbType.UInt16:
                    return Emit.Opc_Conv(ilGen, tNumberA, Reflect.@ushort, CheckOverflow);
                default:
                    return false;
            }
        }

        public static void Opc_Ldarg(ILGenerator ilGen, params int[] args) {

            for (int i = 0, len = args.Length; i < len; i++) {
                int arg_i = args[i];

                switch (arg_i) {
                    case 0:
                        ilGen.Emit(OpCodes.Ldarg_0);
                        break;
                    case 1:
                        ilGen.Emit(OpCodes.Ldarg_1);
                        break;
                    case 2:
                        ilGen.Emit(OpCodes.Ldarg_2);
                        break;
                    case 3:
                        ilGen.Emit(OpCodes.Ldarg_3);
                        break;
                    default:
                        ilGen.Emit(OpCodes.Ldarg, arg_i);
                        break;
                }
            }

        }

        public static void Opc_Ldarga(ILGenerator ilGen, params int[] args) {

            for (int i = 0, len = args.Length; i < len; i++) {
                ilGen.Emit(OpCodes.Ldarga, args[i]);
            }

        }

        public static void Opc_Ldloc(ILGenerator ilGen, params LocalBuilder[] lvParams) {
            if (lvParams == null || lvParams.Length == 0) {
                return;
            }

            for (int i = 0, len = lvParams.Length; i < len; i++) {
                LocalBuilder lvParam_i = lvParams[i];
                if (lvParam_i == null) {
                    continue;
                }

                ilGen.Emit(OpCodes.Ldloc, lvParam_i);
            }
        }

        public static void Opc_Ldloca(ILGenerator ilGen, params LocalBuilder[] lvParams) {
            if (lvParams == null || lvParams.Length == 0) {
                return;
            }

            for (int i = 0, len = lvParams.Length; i < len; i++) {
                LocalBuilder lvParam_i = lvParams[i];
                if (lvParam_i == null) {
                    continue;
                }

                ilGen.Emit(OpCodes.Ldloca, lvParam_i);
            }
        }

        internal static void Opc_Ldind(Type tObj, ILGenerator ilGen) {
            if (tObj.IsClass) {
                ilGen.Emit(OpCodes.Ldind_Ref);
            } else if (ld_Ref.ContainsKey(tObj)) {
                ilGen.Emit(ld_Ref[tObj]);
            } else {
                ilGen.Emit(OpCodes.Ldobj, tObj);
            }
        }

        internal static void Opc_Stind(Type tObj, ILGenerator ilGen) {
            if (tObj.IsClass) {
                ilGen.Emit(OpCodes.Stind_Ref);
            } else if (st_Ref.ContainsKey(tObj)) {
                ilGen.Emit(st_Ref[tObj]);
            } else {
                ilGen.Emit(OpCodes.Stobj, tObj);
            }
        }

        public static void Opc_Ldc(ILGenerator ilGen, int I4) {
            switch (I4) {
                case -1:
                    ilGen.Emit(OpCodes.Ldc_I4_M1);
                    break;
                case 0:
                    ilGen.Emit(OpCodes.Ldc_I4_0);
                    break;
                case 1:
                    ilGen.Emit(OpCodes.Ldc_I4_1);
                    break;
                case 2:
                    ilGen.Emit(OpCodes.Ldc_I4_2);
                    break;
                case 3:
                    ilGen.Emit(OpCodes.Ldc_I4_3);
                    break;
                case 4:
                    ilGen.Emit(OpCodes.Ldc_I4_4);
                    break;
                case 5:
                    ilGen.Emit(OpCodes.Ldc_I4_5);
                    break;
                case 6:
                    ilGen.Emit(OpCodes.Ldc_I4_6);
                    break;
                case 7:
                    ilGen.Emit(OpCodes.Ldc_I4_7);
                    break;
                case 8:
                    ilGen.Emit(OpCodes.Ldc_I4_8);
                    break;
                default:
                    ilGen.Emit(OpCodes.Ldc_I4, I4);
                    break;
            }
        }

        public static void Opc_Ldc(ILGenerator ilGen, long I8) {
            ilGen.Emit(OpCodes.Ldc_I8);
        }

        public static void Opc_Ldc(ILGenerator ilGen, float R4) {
            ilGen.Emit(OpCodes.Ldc_R4, R4);
        }

        public static void Opc_Ldc(ILGenerator ilGen, double R8) {
            ilGen.Emit(OpCodes.Ldc_R8, R8);
        }

        public static void Opc_Call(ILGenerator ilGen, MethodInfo m) {
            ilGen.Emit(((m.IsAbstract || m.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call), m);
        }

        public static void Opc_Set(ILGenerator ilGen, PropertyInfo p) {
            MethodInfo pSet = p.GetSetMethod(true);
            ilGen.Emit(pSet.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, pSet);
        }

        public static void Opc_Get(ILGenerator ilGen, PropertyInfo p) {
            MethodInfo pGet = p.GetGetMethod(true);
            ilGen.Emit(pGet.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, pGet);
        }

        static readonly FieldInfo fldDbNullValue =
            typeof(DBNull).GetField("Value", BindingFlags.Public | BindingFlags.Static);
        public static void Opc_Get(bool IsNullable, Label lbIfNullIgnore,
            Type Tproperty, MethodInfo pGet, ILGenerator ilGen, bool IsDBNull, bool IsBox = true, DbType? dbType = null) {
            //要区分Call和Callvirt
            //ilGen.Emit(OpCodes.Callvirt, pGet);
            Emit.Opc_Call(ilGen, pGet);
            if (IsNullable) {
                LocalBuilder lvNull = ilGen.DeclareLocal(Tproperty);
                Label lbHasValue = ilGen.DefineLabel();
                Label lbSetValue = ilGen.DefineLabel();

                ilGen.Emit(OpCodes.Stloc, lvNull);
                ilGen.Emit(OpCodes.Ldloca, lvNull);
                ilGen.Emit(OpCodes.Call,
                    Tproperty.GetProperty("HasValue").GetGetMethod());
                ilGen.Emit(OpCodes.Brtrue_S, lbHasValue);
                {
                    if (lbIfNullIgnore != null) {
                        ilGen.Emit(OpCodes.Br, lbIfNullIgnore);
                    } else {
                        if (IsDBNull) {
                            ilGen.Emit(OpCodes.Ldsfld, fldDbNullValue);
                        } else {
                            ilGen.Emit(OpCodes.Ldnull);
                        }
                        ilGen.Emit(OpCodes.Br_S, lbSetValue);
                    }
                }
                ilGen.MarkLabel(lbHasValue);
                {
                    ilGen.Emit(OpCodes.Ldloca, lvNull);
                    ilGen.Emit(OpCodes.Call, Tproperty.GetProperty("Value").GetGetMethod());
                    Type tPrimitive = Nullable.GetUnderlyingType(Tproperty);
                    if (tPrimitive.IsValueType) {
                        if(IsBox) {
                            ilGen.Emit(OpCodes.Box, tPrimitive);
                        }
                    }
                }
                ilGen.MarkLabel(lbSetValue);
            } else {
                if (Tproperty.IsValueType) {
                    if(IsBox) {
                        ilGen.Emit(OpCodes.Box, Tproperty);
                    }
                } else {
                    ilGen.Emit(OpCodes.Dup);
                    ilGen.Emit(OpCodes.Ldnull);
                    ilGen.Emit(OpCodes.Ceq);

                    Label lbHasValue = ilGen.DefineLabel();
                    ilGen.Emit(OpCodes.Brfalse_S, lbHasValue);
                    {
                        ilGen.Emit(OpCodes.Pop);
                        if (IsDBNull) {
                            ilGen.Emit(OpCodes.Ldsfld, fldDbNullValue);
                        } else {
                            ilGen.Emit(OpCodes.Ldnull);
                        }
                    }
                    ilGen.MarkLabel(lbHasValue);
                }
            }
        }

        internal static void Opc_Ldtype(ILGenerator ilGen, Type tObj) {
            if (tObj.IsByRef) {
                ilGen.Emit(OpCodes.Ldtoken, tObj.GetElementType());
                ilGen.Emit(OpCodes.Call, Emit.miTgetHandle);
                ilGen.Emit(OpCodes.Callvirt, Emit.miMakeByRef);
            } else {
                ilGen.Emit(OpCodes.Ldtoken, tObj);
                ilGen.Emit(OpCodes.Call, Emit.miTgetHandle);
            }
        }

        public static void Opc_GetAssemblyQualifiedName(Type tObj, ILGenerator ilGen) {
            Emit.Opc_Ldtype(ilGen, tObj);
            Emit.Opc_Get(ilGen, Emit.pAssemblyQualifiedName);
        }
    }
    #endregion Opc

    #region AOP

    public partial class Emit {

        public static InitSignature<Tobj> GenCtor<Tobj>(params Type[] Tparams) {
            Type tObj = typeof(Tobj);
            ConstructorInfo c = tObj.GetConstructor(Tparams);
            if (c == null) {
                throw new Exception();
            }

            DynamicMethod dm =
                new DynamicMethod("", typeof(Tobj), new Type[] { typeof(object[]) }, true);
            ILGenerator ilGen = dm.GetILGenerator();
            {
                Emit.GenInvoker(ilGen, tObj, Tparams, c, false);
            }
            return dm.CreateDelegate(typeof(InitSignature<Tobj>)) as InitSignature<Tobj>;
        }

        public static InvokeSignature GenCtor(Type tObj, params Type[] Tparams) {
            ConstructorInfo mCtor = Reflect.GetCtor(tObj, Tparams);

            DynamicMethod dm =
                new DynamicMethod("", typeof(object), new Type[] { typeof(object), typeof(object[]) }, true);

            ILGenerator ilGen = dm.GetILGenerator();
            Emit.GenInvoker(ilGen, tObj, Tparams, mCtor, true);
            return dm.CreateDelegate(typeof(InvokeSignature)) as InvokeSignature;
        }

        public static SetSignature<Tobj, Tprop> GenSetter<Tobj, Tprop>(string Name) {
            return GenSetter<Tobj, Tprop>(Class<Tobj>.GetMap(Name));
        }

        public static SetSignature<Tobj, Tprop> GenSetter<Tobj, Tprop>(Class<Tobj>.Property P) {
            DynamicMethod dm =
                new DynamicMethod("set_" + P.Name, typeof(void), new Type[] { P.Parent, P.pType }, true);
            {
                ILGenerator ilGen = dm.GetILGenerator();
                if (!P.set.IsStatic) {
                    ilGen.Emit(OpCodes.Ldarg_0);
                }
                ilGen.Emit(OpCodes.Ldarg_1);
                Emit.Opc_Call(ilGen, P.set);
                ilGen.Emit(OpCodes.Ret);
            }
            SetSignature<Tobj, Tprop> S =
                dm.CreateDelegate(typeof(SetSignature<Tobj, Tprop>)) as SetSignature<Tobj, Tprop>;

            return S;
        }

        public static InvokeSignature GenSetter(Type tObj, string Name) {
            try {
                PropertyInfo pObj = Reflect.GetProperty(tObj, Name);
                MethodInfo mInvoke = pObj.GetSetMethod(true);

                DynamicMethod dm =
                    new DynamicMethod("", typeof(object), new Type[] { typeof(object), typeof(object[]) }, true);

                ILGenerator ilGen = dm.GetILGenerator();

                Emit.GenInvoker(ilGen, tObj, new Type[] { pObj.PropertyType }, mInvoke, true, true);

                return dm.CreateDelegate(typeof(InvokeSignature)) as InvokeSignature;
            } catch (Exception ex) {
                throw new CoreException(ex, "Error On Emit.GenSetter[{0}]@[{1}]", Name, tObj.FullName);
            }
        }

        public static GetSignature<Tobj, Tprop> GenGetter<Tobj, Tprop>(string Name) {
            Class<Tobj>.Property P = Class<Tobj>.GetMap(Name);
            return GenGetter<Tobj, Tprop>(P);
        }

        public static GetSignature<Tobj, Tprop> GenGetter<Tobj, Tprop>(Class<Tobj>.Property P) {
            DynamicMethod dm =
                new DynamicMethod("get_" + P.Name, P.pType, new Type[] { P.Parent }, true);
            {
                ILGenerator ilGen = dm.GetILGenerator();
                if (!P.get.IsStatic) {
                    ilGen.Emit(OpCodes.Ldarg_0);
                }
                ilGen.Emit(OpCodes.Call, P.get);
                ilGen.Emit(OpCodes.Ret);
            }

            GetSignature<Tobj, Tprop> G =
                dm.CreateDelegate(typeof(GetSignature<Tobj, Tprop>)) as GetSignature<Tobj, Tprop>;

            return G;
        }

        public static InvokeSignature GenGetter(Type tObj, string Name) {
            PropertyInfo pObj = Reflect.GetProperty(tObj, Name);
            MethodInfo mInvoke = pObj.GetGetMethod(true);

            DynamicMethod dm =
                new DynamicMethod("", typeof(object), new Type[] { typeof(object), typeof(object[]) }, true);

            ILGenerator ilGen = dm.GetILGenerator();

            Emit.GenInvoker(ilGen, tObj, Type.EmptyTypes, mInvoke, true, true);

            return dm.CreateDelegate(typeof(InvokeSignature)) as InvokeSignature;
        }

        public static CallSignature<Tobj> GenCaller<Tobj>(string Name, params Type[] Tparams) {
            Type tObj = typeof(Tobj);
            MethodInfo mCall = Reflect.GetMethod(tObj, Name, Tparams);
            if (mCall == null) {
                throw new Exception();
            }

            DynamicMethod dm =
                new DynamicMethod(Name, typeof(void), new Type[] { tObj, typeof(object[]) }, true);
            ILGenerator ilGen = dm.GetILGenerator();
            Emit.GenInvoker(ilGen, tObj, Tparams, mCall, false, false);
            CallSignature<Tobj> C = dm.CreateDelegate(typeof(CallSignature<Tobj>)) as CallSignature<Tobj>;

            return C;
        }

        public static CallSignature<Tobj, TReturn> GenCaller<Tobj, TReturn>(string Name, params Type[] Tparams) {
            Type tObj = typeof(Tobj);
            MethodInfo mCall = Reflect.GetMethod(tObj, Name, Tparams);
            if (mCall == null) {
                throw new Exception();
            }

            DynamicMethod dm =
                new DynamicMethod(Name, typeof(TReturn), new Type[] { tObj, typeof(object[]) }, true);
            ILGenerator ilGen = dm.GetILGenerator();
            Emit.GenInvoker(ilGen, tObj, Tparams, mCall, false, true);
            CallSignature<Tobj, TReturn> C =
                dm.CreateDelegate(typeof(CallSignature<Tobj, TReturn>)) as CallSignature<Tobj, TReturn>;

            return C;
        }

        public static InvokeSignature GenCaller(Type tObj, Type[] Tgenerics, string Name, params Type[] Tparams) {
            if (Tgenerics == null || Tgenerics.Length == 0) {
                return Emit.GenCaller(tObj, Name, Tparams);
            }

            MethodInfo mInvoke = Reflect.GetMethod(tObj, Name, null);
            mInvoke = mInvoke.MakeGenericMethod(Tgenerics);

            DynamicMethod dm =
                new DynamicMethod("", typeof(object), new Type[] { typeof(object), typeof(object[]) }, true);

            ILGenerator ilGen = dm.GetILGenerator();
            Emit.GenInvoker(ilGen, tObj, Tparams, mInvoke, true, true);
            return dm.CreateDelegate(typeof(InvokeSignature)) as InvokeSignature;
        }

        public static InvokeSignature GenCaller(Type tObj, string Name, params Type[] Tparams) {
            MethodInfo mInvoke = Reflect.GetMethod(tObj, Name, Tparams);
            if (mInvoke == null) {
                throw new CoreException("方法【{0}@{1}】未找到", Name, tObj.FullName);
            }

            return GenCaller(tObj, mInvoke, Tparams);
        }

        public static InvokeSignature GenCaller(Type tObj, MethodInfo mInvoke, params Type[] Tparams) {
            DynamicMethod dm =
                new DynamicMethod("", typeof(object), new Type[] { typeof(object), typeof(object[]) }, true);

            ILGenerator ilGen = dm.GetILGenerator();
            Emit.GenInvoker(ilGen, tObj, Tparams, mInvoke, true, true);
            return dm.CreateDelegate(typeof(InvokeSignature)) as InvokeSignature;
        }

        public static void GenInvoker(ILGenerator ilGen, Type tObj, Type[] Tparams, ConstructorInfo c, bool IsTowParams) {
            GenMethodBody(ilGen, tObj, c, null, IsTowParams, true, Tparams);
        }

        public static void GenInvoker(ILGenerator ilGen, Type tObj, Type[] Tparams, MethodInfo m, bool IsTowParams, bool HasValue) {
            GenMethodBody(ilGen, tObj, null, m, IsTowParams, HasValue, Tparams);
        }

        static FieldInfo fiCacheEventStatus = Reflect.GetField<Emit>("CacheEventStatus");
        static MethodInfo miGetEventStatus = typeof(Dictionary<string, EventStatus>).GetProperty("Item").GetGetMethod();
        internal static Dictionary<string, EventStatus> CacheEventStatus = new Dictionary<string, EventStatus>();

        public static EventStatus GenEvent<Tobj, Tstate>(string Name, object objContext, OnRaise<Tstate> Raise, Tstate State) {
            Type tObj = typeof(Tobj);
            EventInfo ei = Reflect.GetEvent<Tobj>(Name);
            string Key = string.Format("{0}({1})@{2}", Name, Raise.GetHashCode(), tObj.AssemblyQualifiedName);

            lock (Emit.CacheEventStatus) {
                if (Emit.CacheEventStatus.ContainsKey(Key)) {
                    return null;
                } else {
                    return Emit.GenEvent(Key, ei, tObj, ei.EventHandlerType, objContext, Raise, State);
                }
            }
        }

        public static EventStatus GenEvent(Type tObj, string Name, object objContext, OnRaise<object> Raise, object State) {
            EventInfo ei = Reflect.GetEvent(tObj, Name);
            string Key = string.Format("{0}({1})@{2}", Name, Raise.GetHashCode(), tObj.AssemblyQualifiedName);

            lock (Emit.CacheEventStatus) {
                if (Emit.CacheEventStatus.ContainsKey(Key)) {
                    return null;
                } else {
                    return Emit.GenEvent(Key, ei, tObj, ei.EventHandlerType, objContext, Raise, State);
                }
            }
        }

        static void GenMethodBody(ILGenerator ilGen, Type tObj, ConstructorInfo c, MethodInfo m, bool IsTwoParams, bool HasValue, Type[] Tparams) {
            if (c == null && m == null) {
                throw new CoreException("");
            } else if (c != null && m != null) {
                throw new CoreException("");
            }

            List<int> ParamsByRef = new List<int>();
            if (c == null && !m.IsStatic) {
                ilGen.Emit(OpCodes.Ldarg_0);
                if (tObj != Reflect.@object) {
                    ilGen.Emit(OpCodes.Isinst, tObj);
                }
            }
            bool IsByRef = false;
            Type Tparam = null;
            for (int i = 0, len = Tparams.Length; i < len; i++) {
                IsByRef = false;
                Tparam = Tparams[i];
                if (Tparam.IsByRef) {
                    IsByRef = true;
                    Tparam = Tparam.GetElementType();
                }

                ilGen.Emit(c != null && !IsTwoParams ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Ldc_I4, i);
                ilGen.Emit(OpCodes.Ldelem_Ref);
                ilGen.Emit(OpCodes.Unbox_Any, Tparam);
                if (IsByRef) {
                    LocalBuilder lvValue = ilGen.DeclareLocal(Tparam);
                    ilGen.Emit(OpCodes.Stloc, lvValue);
                    ilGen.Emit(OpCodes.Ldloca, lvValue);

                    ParamsByRef.Add(i);
                }
            }
            if (c != null) {
                ilGen.Emit(OpCodes.Newobj, c);
            } else {
                Emit.Opc_Call(ilGen, m);
            }
            foreach (int lvIndex in ParamsByRef) {//保存引用结果值
                ilGen.Emit(c != null ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Ldc_I4, lvIndex);
                ilGen.Emit(OpCodes.Ldloc, lvIndex);
                ilGen.Emit(OpCodes.Box, Tparams[lvIndex].GetElementType());
                ilGen.Emit(OpCodes.Stelem_Ref);
            }

            if (m != null) {
                if (m.ReturnType == Reflect.@void) {
                    if (HasValue) {
                        ilGen.Emit(OpCodes.Ldnull);
                    }
                } else if (!m.ReturnType.IsClass/* m.ReturnType.IsValueType || m.ReturnType.IsEnum || m.ReturnType == Reflect.@DateTime*/) {
                    ilGen.Emit(OpCodes.Box, m.ReturnType);
                }
            }

            ilGen.Emit(OpCodes.Ret);
        }

        static EventStatus GenEvent<Tstate>(string Name, EventInfo ei, Type tParent, Type tEvent, object objContext, OnRaise<Tstate> Raise, object Status) {
            MethodInfo mInvoke = tEvent.GetMethod("Invoke");
            ParameterInfo[] P = mInvoke.GetParameters();
            Type[] TP = new Type[P.Length];
            List<int> ParamsByRef = new List<int>();
            for (int i = 0; i < P.Length; i++) {
                TP[i] = P[i].ParameterType;
            }

            DynamicMethod dm =
                new DynamicMethod(Name, mInvoke.ReturnType, TP, true);
            ILGenerator ilGen = dm.GetILGenerator();
            LocalBuilder lvParams = ilGen.DeclareLocal(typeof(object[]));
            ilGen.Emit(OpCodes.Ldc_I4, TP.Length);
            ilGen.Emit(OpCodes.Newarr, typeof(object));
            ilGen.Emit(OpCodes.Stloc, lvParams);

            bool IsByRef = false;
            Type Tp = null;
            for (int i = 0; i < TP.Length; i++) {
                IsByRef = false;
                Tp = TP[i];
                if (Tp.IsByRef) {
                    IsByRef = true;
                    Tp = Tp.GetElementType();
                    ParamsByRef.Add(i);
                }

                ilGen.Emit(OpCodes.Ldloc, lvParams);
                ilGen.Emit(OpCodes.Ldc_I4, i);
                ilGen.Emit(OpCodes.Ldarg, i);
                if (IsByRef) {
                    Emit.Opc_Ldind(Tp, ilGen);
                }
                if (Tp.IsValueType) {
                    ilGen.Emit(OpCodes.Box, Tp);
                }
                ilGen.Emit(OpCodes.Stelem_Ref);
            }

            LocalBuilder lvStatus = ilGen.DeclareLocal(typeof(EventStatus));
            ilGen.Emit(OpCodes.Ldsfld, Emit.fiCacheEventStatus);
            ilGen.Emit(OpCodes.Ldstr, Name);
            ilGen.Emit(OpCodes.Callvirt, Emit.miGetEventStatus);
            ilGen.Emit(OpCodes.Stloc, lvStatus);

            if (!Raise.Method.IsStatic) {//Load Context
                ilGen.Emit(OpCodes.Ldloc, lvStatus);
                ilGen.Emit(OpCodes.Callvirt, EventStatus.miGetContext);
                ilGen.Emit(OpCodes.Isinst, Raise.Method.DeclaringType); //TODO:如果没有这一句，运行时因为无法判断类型，会报“影响运行时稳定性”错误
            }

            {//Load Status
                ilGen.Emit(OpCodes.Ldloc, lvStatus);
                ilGen.Emit(OpCodes.Callvirt, EventStatus.miGetStatus);
                Type tState = typeof(Tstate);
                ilGen.Emit(OpCodes.Isinst, tState);
            }
            ilGen.Emit(OpCodes.Ldloc, lvParams); //Load ArgValues
            ilGen.Emit(OpCodes.Call, Raise.Method);
            if (mInvoke.ReturnType == Reflect.@void) {
                ilGen.Emit(OpCodes.Pop);
            } else if (mInvoke.ReturnType != Reflect.@object) {
                ilGen.Emit(OpCodes.Unbox_Any, mInvoke.ReturnType);
            }

            foreach (int i in ParamsByRef) {
                Tp = TP[i].GetElementType();
                ilGen.Emit(OpCodes.Ldarg, i);

                ilGen.Emit(OpCodes.Ldloc, lvParams);
                ilGen.Emit(OpCodes.Ldc_I4, i);
                ilGen.Emit(OpCodes.Ldelem_Ref);
                ilGen.Emit(OpCodes.Unbox_Any, Tp);

                Emit.Opc_Stind(Tp, ilGen);
            }

            ilGen.Emit(OpCodes.Ret);

            Delegate d = dm.CreateDelegate(tEvent);

            EventStatus es = new EventStatus(Name, ei, d, objContext, Raise.Target, Status);
            Emit.CacheEventStatus.Add(Name, es); es.Enabled = true;

            return es;
        }
    }
    #endregion AOP

    #region Comparer

    public partial class Emit {
        public static Call<int, T, T> Comparer<T>(params Class<T>.Property[] Params) {
            return Emit.Comparer<T>((Exec<string, int, object, object>)null, Params);
        }

        public static Call<int, T, T> Comparer<T>(Exec<string, int, object, object> showDiff, params Class<T>.Property[] Params) {

            Type T_Clare = typeof(T);
            Class<T>.Property[] P =
                Params == null || Params.Length == 0 ? Class<T>.GetMap() : Params;

            DynamicMethod dmComparer =
                new DynamicMethod("", Reflect.@int, new Type[] { T_Clare, T_Clare }, true);
            Type T_Comparable = typeof(IComparable<string>).GetGenericTypeDefinition();

            ILGenerator ilGen = dmComparer.GetILGenerator();
            LocalBuilder lvResult = ilGen.DeclareLocal(Reflect.@int);

            Label lbReturn = ilGen.DefineLabel();

            LocalBuilder lvName = ilGen.DeclareLocal(Reflect.@string);
            LocalBuilder lv_arg0 = ilGen.DeclareLocal(Reflect.@object);
            LocalBuilder lv_arg1 = ilGen.DeclareLocal(Reflect.@object);

            LocalBuilder lvHasNotValue_Arg0 = ilGen.DeclareLocal(Reflect.@bool);
            LocalBuilder lvHasNotValue_Arg1 = ilGen.DeclareLocal(Reflect.@bool);
            Dictionary<Type, LocalBuilder> lvValues_Arg0 = new Dictionary<Type, LocalBuilder>();
            Dictionary<Type, LocalBuilder> lvValues_Arg1 = new Dictionary<Type, LocalBuilder>();

            for (int i = 0, len_max = P.Length - 1; i <= len_max; i++) {

                Class<T>.Property p_i = P[i];
                bool Order_IsASC =
                    (p_i.IsASC == null || p_i.IsASC.Value) ? true : false;

                Label lbNextProperty = ilGen.DefineLabel();
                {
                    if (showDiff != null) {
                        ilGen.Emit(OpCodes.Ldstr, p_i.Name);
                        ilGen.Emit(OpCodes.Stloc, lvName);
                    }

                    if (!lvValues_Arg0.ContainsKey(p_i.pType)) {
                        lvValues_Arg0.Add(p_i.pType, ilGen.DeclareLocal(p_i.pType));
                    }
                    if (!lvValues_Arg1.ContainsKey(p_i.pType)) {
                        lvValues_Arg1.Add(p_i.pType, ilGen.DeclareLocal(p_i.pType));
                    }
                    if (p_i.IsNullable) {
                        if (!lvValues_Arg0.ContainsKey(p_i.pTypeNull)) {
                            lvValues_Arg0.Add(p_i.pTypeNull, ilGen.DeclareLocal(p_i.pTypeNull));
                        }
                        if (!lvValues_Arg1.ContainsKey(p_i.pTypeNull)) {
                            lvValues_Arg1.Add(p_i.pTypeNull, ilGen.DeclareLocal(p_i.pTypeNull));
                        }
                    }
                }

                Type p_i_type = p_i.IsNullable ? p_i.pTypeNull : p_i.pType;
                Type type_comparable = T_Comparable.MakeGenericType(p_i_type);

                //ld_arg0.value
                ilGen.Emit(OpCodes.Ldarg_0); ilGen.Emit(p_i.IsString ? OpCodes.Callvirt : OpCodes.Call, p_i.get);
                ilGen.Emit(OpCodes.Stloc, lvValues_Arg0[p_i.pType]);
                //ld_arg1.value
                ilGen.Emit(OpCodes.Ldarg_1); ilGen.Emit(p_i.IsString ? OpCodes.Callvirt : OpCodes.Call, p_i.get); ;
                ilGen.Emit(OpCodes.Stloc, lvValues_Arg1[p_i.pType]);

                if (showDiff != null) {//Cache arg0,arg1
                    ilGen.Emit(OpCodes.Ldloc, lvValues_Arg0[p_i.pType]);
                    if (p_i.IsValueType) {
                        ilGen.Emit(OpCodes.Box, p_i.pType);
                    }
                    ilGen.Emit(OpCodes.Stloc, lv_arg0);

                    ilGen.Emit(OpCodes.Ldloc, lvValues_Arg1[p_i.pType]);
                    if (p_i.IsValueType) {
                        ilGen.Emit(OpCodes.Box, p_i.pType);
                    }
                    ilGen.Emit(OpCodes.Stloc, lv_arg1);
                }

                if (HasInterface(p_i_type, type_comparable)) {
                    MethodInfo m_compareto =
                        p_i_type.GetMethod("CompareTo", new Type[] { p_i_type });

                    if (p_i.IsNullable || !p_i.IsValueType) {
                        Label lbAllNotNull = ilGen.DefineLabel();

                        PropertyInfo p_hasValue = null; MethodInfo m_HasValue = null;
                        PropertyInfo p_Value = null; MethodInfo m_Value = null;
                        if (p_i.IsNullable) {
                            p_hasValue = p_i.pType.GetProperty("HasValue"); m_HasValue = p_hasValue.GetGetMethod();
                            p_Value = p_i.pType.GetProperty("Value"); m_Value = p_Value.GetGetMethod();

                            //get.!HasValue_0
                            ilGen.Emit(OpCodes.Ldloca, lvValues_Arg0[p_i.pType]);
                            ilGen.Emit(OpCodes.Call, m_HasValue);
                            ilGen.Emit(OpCodes.Ldc_I4_0);
                            ilGen.Emit(OpCodes.Ceq);
                            ilGen.Emit(OpCodes.Stloc, lvHasNotValue_Arg0);

                            //get.!HasValue_1
                            ilGen.Emit(OpCodes.Ldloca, lvValues_Arg1[p_i.pType]);
                            ilGen.Emit(OpCodes.Call, m_HasValue);
                            ilGen.Emit(OpCodes.Ldc_I4_0);
                            ilGen.Emit(OpCodes.Ceq);
                            ilGen.Emit(OpCodes.Stloc, lvHasNotValue_Arg1);
                        } else {
                            //get.!HasValue_0
                            ilGen.Emit(OpCodes.Ldloc, lvValues_Arg0[p_i_type]);
                            ilGen.Emit(OpCodes.Ldnull);
                            ilGen.Emit(OpCodes.Ceq);
                            ilGen.Emit(OpCodes.Stloc, lvHasNotValue_Arg0);

                            //get.!HasValue_0
                            ilGen.Emit(OpCodes.Ldloc, lvValues_Arg1[p_i_type]);
                            ilGen.Emit(OpCodes.Ldnull);
                            ilGen.Emit(OpCodes.Ceq);
                            ilGen.Emit(OpCodes.Stloc, lvHasNotValue_Arg1);
                        }

                        Label lbCheckWhichIsNull = ilGen.DefineLabel();
                        //if(!HasValue_0 && !HasValue_1){
                        ilGen.Emit(OpCodes.Ldloc, lvHasNotValue_Arg0);
                        ilGen.Emit(OpCodes.Ldloc, lvHasNotValue_Arg1);
                        ilGen.Emit(OpCodes.Ceq);
                        ilGen.Emit(OpCodes.Brfalse, lbCheckWhichIsNull);
                        ilGen.Emit(OpCodes.Ldloc, lvHasNotValue_Arg0);
                        ilGen.Emit(OpCodes.Brfalse, lbAllNotNull);
                        {//All Has Not Value
                            ilGen.Emit(OpCodes.Ldc_I4_0);
                            ilGen.Emit(OpCodes.Stloc, lvResult);
                            ilGen.Emit(OpCodes.Br, lbNextProperty);
                        }

                        ilGen.MarkLabel(lbCheckWhichIsNull);
                        {
                            //} else if(!HasValue_1) {
                            //  reuturn 1;
                            Label lb_arg0_IsNull = ilGen.DefineLabel();
                            ilGen.Emit(OpCodes.Ldloc, lvHasNotValue_Arg1);
                            ilGen.Emit(OpCodes.Brfalse, lb_arg0_IsNull);
                            ilGen.Emit(OpCodes.Ldc_I4_1);
                            ilGen.Emit(OpCodes.Stloc, lvResult);
                            ilGen.Emit(OpCodes.Br, lbNextProperty);
                            //} else if(!HasValue_0) {
                            //  return -1
                            ilGen.MarkLabel(lb_arg0_IsNull);
                            ilGen.Emit(OpCodes.Ldc_I4_M1);
                            ilGen.Emit(OpCodes.Stloc, lvResult);
                            ilGen.Emit(OpCodes.Br, lbNextProperty);
                        }
                        //} else {
                        ilGen.MarkLabel(lbAllNotNull);
                        {
                            //ld_arg0
                            if (p_i.IsNullable) {
                                ilGen.Emit(OpCodes.Ldloca, lvValues_Arg0[p_i.pType]);
                                ilGen.Emit(OpCodes.Call, m_Value);
                                ilGen.Emit(OpCodes.Stloc, lvValues_Arg0[p_i_type]);
                            }

                            //ld_arg1
                            if (p_i.IsNullable) {
                                ilGen.Emit(OpCodes.Ldloca, lvValues_Arg1[p_i.pType]);
                                ilGen.Emit(OpCodes.Call, m_Value);
                                ilGen.Emit(OpCodes.Stloc, lvValues_Arg1[p_i_type]);
                            }
                        }
                    }
                    {//CompareTo<T>(T v);
                        {
                            ilGen.Emit(p_i.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc, lvValues_Arg0[p_i_type]);
                            ilGen.Emit(OpCodes.Ldloc, lvValues_Arg1[p_i_type]);
                        }
                        ilGen.Emit(p_i.IsString ? OpCodes.Callvirt : OpCodes.Call, m_compareto);
                    }
                    ilGen.Emit(OpCodes.Stloc, lvResult);

                    ilGen.MarkLabel(lbNextProperty);
                    if (i < len_max) {
                        ilGen.Emit(OpCodes.Ldloc, lvResult);
                        if (!Order_IsASC) {
                            ilGen.Emit(OpCodes.Neg);
                        }
                        ilGen.Emit(OpCodes.Brtrue, lbReturn);
                    } else {
                        if (!Order_IsASC) {
                            ilGen.Emit(OpCodes.Ldloc, lvResult);
                            ilGen.Emit(OpCodes.Neg);
                            ilGen.Emit(OpCodes.Stloc, lvResult);
                        }
                    }
                } else {
                    //TODO:throw new CoreException("{0}:Type [{1}] Not Support By Emit.Comparer", p_i.Name, p_i.pType.AssemblyQualifiedName);
                }
            }

            ilGen.MarkLabel(lbReturn);
            if (showDiff != null) {
                Label lbHopDiff = ilGen.DefineLabel();
                ilGen.Emit(OpCodes.Ldloc, lvResult);
                ilGen.Emit(OpCodes.Brfalse, lbHopDiff);
                Emit.Opc_Ldloc(ilGen,
                    lvName, lvResult, lv_arg0, lv_arg1);
                ilGen.Emit(OpCodes.Call, showDiff.Method);
                ilGen.MarkLabel(lbHopDiff);
            }
            ilGen.Emit(OpCodes.Ldloc, lvResult);
            ilGen.Emit(OpCodes.Ret);

            return dmComparer.CreateDelegate(typeof(Call<int, T, T>)) as Call<int, T, T>;
        }

        static bool HasInterface(Type T_parent, Type T_interface) {
            string name = T_interface.AssemblyQualifiedName;
            Type[] Tinterfaces = T_parent.GetInterfaces();

            for (int i = 0, len = Tinterfaces.Length; i < len; i++) {
                Type t_i = Tinterfaces[i];

                if (t_i.AssemblyQualifiedName == name) {
                    return true;
                }
            }

            return false;
        }
    }
    #endregion Comparer
}
